package office.poi.excel.imp;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import office.poi.excel.bean.ExcelColumnBean;
import office.poi.excel.utils.BeanUtils;
import office.poi.excel.utils.CellUtils;
import office.poi.excel.utils.ErrorMsgUtils;
import office.poi.excel.utils.MsgUtils;
import office.utils.ObjectUtil;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellRangeAddress;

public  class ReadExcel {

	// 是否有错误
	public  Boolean hasError = false;
	// 是否验证错误
	public  Boolean hasErrorValidate = false;
	// 错误信息
	public  StringBuffer errorMsg = new StringBuffer(128);;
	// 验证错误信息
	public  StringBuffer errorValidateMsg = new StringBuffer(128);
	// 可能出现空行 用此标识一整行为空 就是false 就 不加到list
	private  Boolean isAddList = false;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Collection<?> getList(HSSFSheet sheet, List<ExcelColumnBean> ecbList, int totalRow, int row, int[] columns,
			Class clazz) {
		Collection list = new ArrayList();
		Object objClazz = null;

		/**
		 * 遍历表格
		 */
		for (int i = (row + 1); i <= totalRow; i++) {
			try {
				objClazz = clazz.newInstance();
			} catch (Exception e1) {
				hasError = true;
				MsgUtils.addErrorMsg(errorMsg, e1.getMessage());
			}
			for (int j = 0; j < columns.length; j++) {
				ExcelColumnBean ecb = ecbList.get(j);
				/**
				 * 在某行一整行为空的时候，会出现异常 例第一行有数据 第二行为空 第三行有数据 在遍历到第二行的时候会异常 所以扑捉异常
				 * 不做处理 就会继续向下遍历
				 */
				// 根据行列得到表格
				HSSFCell cell = null;
				try {
					cell = CellUtils.getCell(sheet, i, columns[j]);
				} catch (Exception e) {
					hasError = true;
					MsgUtils.addValidateErrorMsg(errorMsg, i + 1, j + 1, "读取时发生错误！");
				}

				// 得到表格内容
				Object objValue = "";
				if (cell != null) {
					objValue = CellUtils.getCellValue(cell);
					// 出现不为空则 改成 true
					if (!isAddList)
						isAddList = ObjectUtil.isNotEmpty(objValue);
				}

				// 合并行的索引
				Set MergedRowIndex = getMergedRowIndex(sheet);

				/**
				 * 验证内容
				 */
				if (ecb.getRequired()) // 是否必填
				{
					if (ObjectUtil.isEmpty(objValue)) {
						boolean IsValidateRequired = true;
						//是否通过 判断 是否有合并单元格 来取消必填验证 
						if (isValidateRequiredByMerged) {
							if (MergedRowIndex.contains(i))
								IsValidateRequired = false;
						} else {
							/**
							 * 出现一整行都为空 视为空， 如果不视为空 必填字段验证不通过 这段代码就是 RowIsEmpty
							 * = false 才验证该列是否为空
							 */

							Iterator<Cell> itCell = sheet.getRow(i).cellIterator();
							getMergedRowIndex(sheet);
							while (itCell.hasNext()) {
								HSSFCell c = (HSSFCell) itCell.next();
								Object o = CellUtils.getCellValue(c);
								if (ObjectUtil.isNotEmpty(o))
									IsValidateRequired = false;
								break;
							}
						}
						if (IsValidateRequired) {
							hasErrorValidate = true;
							MsgUtils.addValidateErrorMsg(errorValidateMsg, i + 1, j + 1, "必填项！");
							break;
						}
					}

				} else if (0 < ecb.getLength() && ecb.getLength() < objValue.toString().length()) {
					hasErrorValidate = true;
					MsgUtils.addValidateErrorMsg(errorValidateMsg, i + 1, j + 1, "字符长度要求是" + ecb.getLength() + "实际是"
							+ objValue.toString().length());
					break;

				} else if (0 < ecb.getPrecision()
						&& ecb.getPrecision() < objValue.toString().substring(0, objValue.toString().lastIndexOf("."))
								.length()) {
					hasErrorValidate = true;
					MsgUtils.addValidateErrorMsg(errorValidateMsg, i + 1, j + 1, "小数点前有效位是要求是" + ecb.getPrecision()
							+ "实际是" + objValue.toString().length());
					break;
				} else if (0 < ecb.getScale()
						&& ecb.getScale() < objValue.toString()
								.substring(objValue.toString().lastIndexOf(".") + 1, objValue.toString().length())
								.length()) {
					hasErrorValidate = true;
					MsgUtils.addValidateErrorMsg(errorValidateMsg, i + 1, j + 1, "小数点后有效位是要求是" + ecb.getPrecision()
							+ "实际是" + objValue.toString().length());
					break;
				}
				if (!ecb.getPropertyType().toString().equals("NULL")) {
					String msg = ErrorMsgUtils.getValidateErrorMsg(ecb.getPropertyType(), objValue.toString());
					if (msg != "") {
						MsgUtils.addValidateErrorMsg(errorValidateMsg, i + 1, j + 1, msg);
						break;
					}

				} else {
					/************************************* 验证检查结束，开始把数据写到实体类中 *****************************************************/
					BeanUtils.addValueToBean(ecb.getBeanName(), objValue, objClazz);
				}
			}
			// isAddList=false是记录用 用完要归位的不然影响结果
			if (isAddList)
				list.add(objClazz);
			isAddList = false;
		}
		return list;
	}

	/**
	 * 得到有合并单元格 的行索引
	 * 
	 * @param sheet
	 * @return
	 */
	private Set<Integer> getMergedRowIndex(HSSFSheet sheet) {
		Set<Integer> set = new HashSet<Integer>();
		// 得到有合并的 个数
		int numMergedRegions = sheet.getNumMergedRegions();
		for (int i = 0; i < numMergedRegions; i++) {
			CellRangeAddress crd = sheet.getMergedRegion(i);
			int rowFirstIndex = crd.getFirstRow();
			set.add(rowFirstIndex);
		}
		return set;
	}

	/**
	 * 验证必填通过合并单元格 验证必填的时候 如果有多个组集合 则不能分辨每个组集合读取的行数 因此通过获取合并行 获取到有发生合并的 行索引
	 * 来进行分组
	 * 
	 * 注意：组集合之间只能有一行
	 * 
	 */
	public  Boolean isValidateRequiredByMerged = true;
}
